package ge.engine;


import java.util.ArrayList;

import ge.modules.Module;

/**
 * 
 * @author Abel
 * One positionable actor has the property of have one own x and y coordinate. 
 */
public class PositionableActor extends Actor implements Positionable {

	private double X,Y;
	private ArrayList<ObjectPosition> attachedElements;
	public PositionableActor()
	{
		super();
		attachedElements = new ArrayList<PositionableActor.ObjectPosition>();
		X = Y = 0;
	}
	
	/**
	 * 	Updates the position of the actor and of their attached elements
	 * @param x 
	 * @param y 
	 */
	@Override
	public void setPos(double x, double y) 
	{
		X = x;
		Y = y;
		for(ObjectPosition obPos : attachedElements)
		{
			obPos.getObject().setPos(X+obPos.getRelativeX(), Y+obPos.getRelativeY());
		}
	}

	/**
	 * 	While set position relative to the coordinates center (0,0),
	 * 	move use the actual position of the actor like coordinates center.
	 *  
	 *  Means, move the actor, anyway,
	 *  
	 * @param x Move x coordinate
	 * @param y Move y coordinate
	 */
	public void move(double x, double y)
	{
		setPos(X+x,y+Y);
	}
	@Override
	public double getX() {
		return X;
	}

	@Override
	public double getY() 
	{
		return Y;
	}

	/**
	 * 	Associates a positionable element with the position of this object.
	 *  It means that if Actor changes it's position, that element will move
	 *  too, exactly at the Actor position plus the X and Y relative coordinate.
	 *  
	 *  If you attach and element, it will be added also if it implements module interface,
	 *   actor will call its update and draw function like the add behavior.   
	 * @param element 
	 * @param x Position relative to the X position of the actor
	 * @param y Position of the relative Y Position of the actor
	 */
	public void attach(Positionable element, double x, double y)
	{
		attachedElements.add(new ObjectPosition(x, y, element));
		element.setPos(X+x, Y+y);	//Updates immediately it's position
		if(element instanceof Module)
			add((Module) element);
	}
	/**
	 * 	Associates a positionable element with the position of this object.
	 *  It means that if Actor changes it's position. Associates at the same
	 *  position that object. If you want to add a relative position use the
	 *  function attach(Positionable,double,double).
	 *  If you attach and element, it will be added also if it implements module interface,
	 *   actor will call its update and draw function like the add behavior.   
	 * @param element
	 */
	public void attach(Positionable element)
	{
		attach(element, 0, 0);
	}
	/**
	 * 	Deattach the element from the actor, and remove from it module's list if element
	 * 	implements Module interface
	 * @param element	Element to be removed
	 */
	public void deattach(Positionable element)
	{
		for(ObjectPosition obPos : attachedElements)
		{
			if(obPos.getObject() == element)
			{
				attachedElements.remove(obPos);
				if(obPos instanceof Module)
					remove((Module)obPos);
				break;
			}
		}
	}
	private class ObjectPosition
	{
		private double relativeX, relativeY;
		private Positionable object;
		/**
		 * 	Attach a positionable element to an Actor
		 * @param X	Relative to the position of the Positionable Actor
		 * @param Y Relative to the position of the Positionable Actor
		 * @param object Positionable Object
		 */
		public ObjectPosition(double X, double Y, Positionable object)
		{
			relativeX = X;
			relativeY = Y;
			this.object = object;
		}
		public double getRelativeX() {
			return relativeX;
		}
		public double getRelativeY() {
			return relativeY;
		}
		public Positionable getObject() {
			return object;
		}
		
	}
}
